package metiers;

import gestionOrdres.LectureFichierOrdre;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.sparql.resultset.ResultSetRewindable;

public class Resultat {

	private List<List<String>> resultats;
	private List<Clustering> clusterings = new ArrayList<Clustering>();
	private Requete requete;
	private List<Concept> listeConceptsParImportance;

	public List<List<String>> getResultats() {
		return resultats;
	}

	public void setResultats(List<List<String>> resultats) {
		this.resultats = resultats;
	}

	public List<Clustering> getClusterings() {
		return clusterings;
	}

	public void setClusterings(List<Clustering> clusterings) {
		this.clusterings = clusterings;
	}

	public Requete getRequete() {
		return requete;
	}

	public void setRequete(Requete requete) {
		this.requete = requete;
	}

	public List<Concept> getListeConceptsParImportance() {
		return listeConceptsParImportance;
	}

	public void setListeConceptsParImportance(
			List<Concept> listeConceptsParImportance) {
		this.listeConceptsParImportance = listeConceptsParImportance;
	}

	/**
	 * Méthode qui récupère les données de la requête, les transforme en chaînes de caractère
	 * lisibles et les insère dans l'attribut resultats.
	 */
	public void recupererDonnees() {

		// On récupère les noms des colonnes contenus dans la première ligne du
		// ResultSet

		resultats = new ArrayList<List<String>>();

		ResultSetRewindable tableau = requete.getTableauDonnees();
		List<String> test2 = tableau.getResultVars();

		QuerySolution ligneCourante = tableau.next();

		System.out.println("requete " + requete.getTableauDonnees().hasNext());

		while (tableau.hasNext()) {
			List<String> ligne = new ArrayList<String>();
			// Pour chaque colonne de la ligne concernée, on va récupérer la
			// valeur prise par le concept.
			for (int i = 0; i < test2.size(); i++) {
				String nomColonne = test2.get(i);
				String valeur = "valeur illisible";
				// On distingue deux cas pour l'affichage : le cas où on a un
				// literal et le cas où on a une URI.
				try {
					valeur = ligneCourante.get(nomColonne).asLiteral()
							.getString();
				} catch (Exception e) {
					try {
						System.out.println(nomColonne);
						valeur = ligneCourante.getResource(nomColonne).getURI();
					} catch (Exception e2) {
						System.out.println("erreur 2");
					}
				}
				// On rajoute le String obtenu à la ligne.
				ligne.add(valeur);
			}
			// Une fois que l'on a fini de récupérer la ligne, on l'ajoute à
			// l'ensemble des lignes et on passe à la suivante.
			resultats.add(ligne);
			ligneCourante = tableau.next();
		}

		// On remet au début le "curseur" du ResultSet
		tableau.reset();

	}

	/**
	 * Permet d'ajouter à la liste courante de clusterings un nouveau clustering
	 * 
	 * @param concept1
	 *            : axe1 du clustering
	 * @param concept2
	 *            : axe2 du clustering
	 */
	public void ajouterClustering(Concept concept1, Concept concept2) {
		// On récupère la liste courante des clusterings
		List<Clustering> listeClusterings = this.getClusterings();

		// On a besoin de savoir à quelle colonne correspond le concept pour
		// faire les bonnes extractions dans l'arrayList. 
		//		int rangConcept1 = 0;
		//		int rangConcept2 = 1;
		//		List<Concept> listeConcepts = requete.getConcepts();
		//		for (Concept concept : listeConcepts) {
		//
		//			if (concept.egaleA(concept1)) {
		//				rangConcept1 = listeConcepts.indexOf(concept);
		//			}
		//			if (concept.egaleA(concept2)) {
		//				rangConcept2 = listeConcepts.indexOf(concept);
		//			}
		//
		//		}
		List<Concept> listeConcepts = new ArrayList<Concept>(); 
		listeConcepts.add(requete.getConceptPrincipal());
		listeConcepts.addAll(requete.getConcepts());
		int rangConcept1 = listeConcepts.indexOf(concept1);
		int rangConcept2 = listeConcepts.indexOf(concept2);
		System.out.println("Concept :"+ concept1.getNom() + " au rang "+ rangConcept1);
		System.out.println("Concept :"+ concept2.getNom() + " au rang "+ rangConcept2);

		// On crée le nouveau clustering correspondant à (concept1,concept2)
		Clustering c = new Clustering(concept1, rangConcept1, concept2,
				rangConcept2, resultats);
		listeClusterings.add(c);

		// On met à jour la liste courante des clusterings
		this.setClusterings(listeClusterings);
	}

	public void ajouterClustering(){

		this.ajouterClustering(requete.getConcepts().get(1),requete.getConcepts().get(2));

	}

	public Clustering getClustering(Concept concept1, Concept concept2) {
		Clustering resultat = new Clustering();
		for (int j = 0; j < clusterings.size(); j++) {
			Clustering clustering = clusterings.get(j);

			if (clustering.getConcept1().equals(concept1)
					&& clustering.getConcept2().equals(concept2)) {
				resultat = clustering;
			}

		}
		return resultat;
	}

	/**
	 * Permet de calculer les meilleurs axes de représentation. Cette méthode remplit l'attribut
	 * listeConceptsParImportance avec la liste des concepts triés par intérêt.
	 * 
	 */
	public void trouverMeilleursAxes(){

		// On crée deux Map qui permettent de calculer les 
		// scores des concepts à partir de leurs classements
		// Quand un concept n'est pas classé dans les 5 premiers, on lui attribue 0 points

		// Première Map qui attribue des points aux concepts en fonction de leur classement 
		// par rapport au concept principal
		Map<Integer,Integer> grilleClassementScorePrincipal = new HashMap<Integer,Integer>();
		grilleClassementScorePrincipal.put(0, 0);
		grilleClassementScorePrincipal.put(1, 100);
		grilleClassementScorePrincipal.put(2, 50);
		grilleClassementScorePrincipal.put(3, 30);
		grilleClassementScorePrincipal.put(4, 15);
		grilleClassementScorePrincipal.put(5, 5);

		// Seconde Map qui attribue des points aux concepts en fonction de leurs classements
		// par rapport aux concepts complémentaires
		Map<Integer,Integer> grilleClassementScoreComplementaire = new HashMap<Integer,Integer>();
		grilleClassementScoreComplementaire.put(0, 0);
		grilleClassementScoreComplementaire.put(1, 10);
		grilleClassementScoreComplementaire.put(2, 5);
		grilleClassementScoreComplementaire.put(3, 3);
		grilleClassementScoreComplementaire.put(4, 2);
		grilleClassementScoreComplementaire.put(5, 1);

		// On récupère les concepts de la requête en cours et 
		// les objets Axe qui contiennent les classements
		System.out.println("On lit les fichiers");
		LectureFichierOrdre l = LectureFichierOrdre.getUniqueLecture();
		System.out.println("sortie de getUniqueLecture()");
		Concept conceptPrincipal = this.getRequete().getConceptPrincipal();
		List<Concept> concepts = this.getRequete().getConcepts();
		System.out.println("on récupère les axes");
		List<Axe> listeAxes = l.getListeAxes();
		System.out.println("tailleAxes : "+listeAxes.size());
		;
		//System.out.println("axe 1 : "+listeAxes.get(0).getConcept().getNom()+" et axe concerné : "+listeAxes.get(0).getConceptAssocie().getNom());
		// On crée une Map qui associe un score (value) à chaque concept (key)
		Map<Concept,Integer> scoresMap = new HashMap<Concept,Integer>();

		// On calcule les scores associés au concept principal
		System.out.println("on commence à parcourir les axes pour leur attribuer un score par rapport au concept principal");
		for (Axe a :listeAxes){
			if(a.getConcept().equals(conceptPrincipal)){
				if(a.getTypeAssociation().equals(typeAssociationConcept.Principal)){
					Concept conceptA = a.getConceptAssocie();
					int rang = a.getPourClassement();
					int scorePrincipal =0;
					if(rang<5){
						scorePrincipal = grilleClassementScorePrincipal.get(rang);
						System.out.println("score pour le concept principal de "+conceptA.getNom()+" : "+scorePrincipal);
					}
					scoresMap.put(conceptA,scorePrincipal);
				}
			}
		}

		// On calcule les scores associés aux concepts complémentaires
		System.out.println("On passe aux concepts complémentaires");
		for(Concept c : concepts){
			for (Axe a :listeAxes){
				if(a.getConcept().equals(c)){
					if(a.getTypeAssociation().equals(typeAssociationConcept.Complementaire)){
						Concept conceptA = a.getConceptAssocie();
						int rang = a.getPourClassement();
						int scoreComplementaire = 0;

						if(rang<5){
							scoreComplementaire = grilleClassementScoreComplementaire.get(rang);
						}
						System.out.println("score pour le concept complementaire"+c.getNom()+"de "+conceptA.getNom()+" : "+scoreComplementaire);

						if(scoresMap.containsKey(conceptA)){
							int scoreAncien = scoresMap.get(conceptA);
							scoresMap.put(conceptA,scoreComplementaire+scoreAncien);
						}
						else{
							scoresMap.put(conceptA,scoreComplementaire);
						}

					}
				}
			}
		}
		System.out.println("taille du hashmap : "+scoresMap.size());
		// On crée une liste triée qu'on va remplir avec les concepts triés dans l'ordre
		// du plus intéressant au moins intéressant
		System.out.println("on commence le tri");
		List<Concept> listeTriee = new ArrayList<Concept>();
		Collection<Integer> listeValeurs = scoresMap.values();
		List<Integer> liste = new ArrayList<Integer>();
		for(Integer i : listeValeurs){
			liste.add(i);
		}
		Collections.sort(liste);

		for(int i=0;i<liste.size()-1;i++){

			if(liste.get(i).equals(liste.get(i+1))){
				liste.remove(i);
			}

		}

		Set<Concept> cles =scoresMap.keySet();
		for(Integer score : liste){
			for(Concept c : cles){
				if(scoresMap.get(c).equals(score)){
					listeTriee.add(c);
				}
			}
		}

		this.setListeConceptsParImportance(listeTriee);
		System.out.println(listeTriee.toString());
	}

}
